use std::{rc::Rc, cell::RefCell, sync::{mpsc::Sender, Arc, Mutex}, collections::HashSet};

use jvm_rust::raw;

use crate::SenderType;

use super::{Stack, Frame, Object, heap::{ClassLoader, Class, string_pool}};

// 线程
pub struct Thread {
    pc: i32, // pc寄存器。存放内容->1、java方法：当前线程正在执行的jvm指令地址 2、native：未定义
    stack: Stack,
    sender: Option<Sender<SenderType>>,
    locks: HashSet<usize>, // 当前线程持有的锁
    j_thread: Option<*mut Object>, // java thread ref
}

unsafe impl Send for Thread { }

impl Thread {
    pub fn new_thread(sender: Option<Sender<SenderType>>) -> Thread {
        Thread {
            pc: 0,
            stack: Stack::new_stack(1024),
            sender,
            locks: HashSet::new(),
            j_thread: None,
        }
    }

    pub fn new_shim_thread(j_thread: Option<*mut Object>) -> Thread {
        Thread {
            pc: 0,
            stack: Stack::new_stack(1024),
            sender: None,
            locks: HashSet::new(),
            j_thread,
        }
    }

    pub fn new_main_thread(loader: Arc<Mutex<ClassLoader>>, sender: Option<Sender<SenderType>>) -> Arc<Mutex<Thread>> {
        let mut thread = Self::new_thread(sender);

        let thread_class = loader.lock().unwrap().load_class("java/lang/Thread".to_string());
        let mut j_thread = Class::new_object(thread_class);

        let thread_group_class = loader.lock().unwrap().load_class("java/lang/ThreadGroup".to_string());
        let j_group = Class::new_object(thread_group_class);

        j_thread.set_ref_var("group", "Ljava/lang/ThreadGroup;", raw!(j_group));
        let j_string = string_pool::j_string(&mut loader.lock().unwrap(), "main");
        j_thread.set_ref_var("name", "Ljava/lang/String;", j_string);
        j_thread.set_int_var("priority", "I", 5);

        thread.j_thread = Some(raw!(j_thread));
        Arc::new(Mutex::new(thread))
    }

    pub fn get_pc(&self) -> i32 {
        self.pc
    }

    pub fn set_pc(&mut self, pc: i32) {
        self.pc = pc;
    }

    pub fn push_frame(&mut self, frame: Frame) {
        self.stack.push(frame)
    }

    pub fn pop_frame(&mut self) -> Rc<RefCell<Frame>> {
        self.stack.pop()
    }

    pub fn current_frame(&self) -> Rc<RefCell<Frame>> {
        self.stack.top()
    }

    pub fn is_stack_empty(&self) -> bool {
      self.stack.is_empty()
    }

    pub fn clear_stack(&mut self) {
        self.stack.clear();
    }

    pub fn get_frames(&self) -> Vec<Rc<RefCell<Frame>>> {
        self.stack.get_frames()
    }

    pub fn clone_sender(&self) -> Option<Sender<SenderType>> {
        if let Some(sender) = &self.sender {
            Some(sender.clone())
        } else {
            None
        }
    }

    pub fn take_sender(&mut self) -> Option<Sender<SenderType>> {
        self.sender.take()
    }

    pub fn set_sender(&mut self,sender: Sender<SenderType>) {
        self.sender = Some(sender);
    }

    pub fn contains_lock(&self, key: usize) -> bool {
        self.locks.contains(&key)
    }

    pub fn insert_lock(&mut self, key: usize) -> bool {
        self.locks.insert(key)
    }

    pub fn remove_lock(&mut self, key: usize) -> bool {
        self.locks.remove(&key)
    }

    pub fn locks(&self) -> &HashSet<usize> {
        &self.locks
    }

    pub fn get_j_thread(&self) -> Option<*mut Object> {
        self.j_thread.clone()
    }

    pub fn set_j_thread(&mut self, j_thread: Option<*mut Object>) {
        self.j_thread = j_thread;
    } 


}
